package org.gdstash.file;

import net.jpountz.lz4.LZ4Factory;
import net.jpountz.lz4.LZ4FastDecompressor;
import org.gdstash.db.DBSkillBonus;
import org.gdstash.db.DBSkillModifier;
import org.gdstash.db.DBStat;
import org.gdstash.db.GDDBData;
import org.gdstash.ui.GDStashFrame;
import org.gdstash.util.GDConstants;
import org.gdstash.util.GDMsgFormatter;
import org.gdstash.util.GDMsgLogger;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.NumberFormat;

public class ARZDecompress {
    public static final short REC_VALUE_INT = 0;
    public static final short REC_VALUE_FLOAT = 1;
    public static final short REC_VALUE_STRING = 2;
    public static final short REC_VALUE_BOOL = 3;
    private String filename;
    private ARZHeader header;
    private ARZString[] strings;
    private ARZRecord[] records;

    public ARZDecompress(final String filename) {
        this.filename = filename;
    }

    public static boolean is64BitVM() {
        final String arch = System.getProperty("os.arch");
        return arch.contains("64");
    }

    public static GDBuffer getFileBuffer(final File file) {
        GDBuffer buffer = null;
        if (is64BitVM()) {
            buffer = new GDMappedByteBuffer(file);
        } else {
            buffer = new GDByteBuffer(file);
        }
        return buffer;
    }

    public void clear() {
        this.header = null;
        this.strings = null;
        this.records = null;
    }

    public void decompress() {
        final boolean extractItems = true;
        try {
            final File file = new File(this.filename);
            if (!file.exists()) {
                final Object[] args = {this.filename};
                final String s = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_FILE_NOT_FOUND", args);
                throw new FileNotFoundException(s);
            }
            if (!file.isFile()) {
                final Object[] args = {this.filename};
                final String s = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_FILE_NOT_FOUND", args);
                throw new FileNotFoundException(s);
            }
            if (!file.canRead()) {
                final Object[] args = {this.filename};
                final String s = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_FILE_CANNOT_READ", args);
                throw new IOException(s);
            }
            GDBuffer buffer = getFileBuffer(file);
            try {
                this.header = getHeader(buffer);
                this.strings = this.getStrings(buffer);
                this.records = this.getRecords(buffer);
                this.extractRecords(buffer, extractItems);
            } catch (IOException ex) {
                throw ex;
            } finally {
                buffer.close();
                buffer = null;
            }
        } catch (Exception ex2) {
            GDMsgLogger.addError(ex2);
        }
        this.resolveAttrib();
        GDStashFrame.listToLog();
        if (GDMsgLogger.severeErrorsInLog()) {
            GDMsgLogger.addError(GDMsgFormatter.getString(GDMsgFormatter.rbMsg, "ERR_DB_EXTRACT_FAIL"));
        }
    }

    private static ARZHeader getHeader(final GDBuffer buffer) throws IOException, GDParseException {
        final ARZHeader header = new ARZHeader();
        header.unknown = buffer.getShort();
        header.version = buffer.getShort();
        header.rec_start = buffer.getInt();
        header.rec_size = buffer.getInt();
        header.rec_num = buffer.getInt();
        header.str_start = buffer.getInt();
        header.str_size = buffer.getInt();
        if (header.unknown != 2 || header.version != 3) {
            throw new GDParseException(GDMsgFormatter.getString(GDMsgFormatter.rbMsg, "ERR_UNSUPPORTED_VERSION"), 0L);
        }
        return header;
    }

    private ARZString[] getStrings(final GDBuffer buffer) throws IOException {
        buffer.setPosition(this.header.str_start);
        final int num = buffer.getInt();
        final ARZString[] strings = new ARZString[num];
        for (int i = 0; i < strings.length; ++i) {
            final ARZString str = buffer.getARZString();
            strings[i] = str;
        }
        return strings;
    }

    private ARZRecord[] getRecords(final GDBuffer buffer) throws IOException {
        final ARZRecord[] records = new ARZRecord[this.header.rec_num];
        buffer.setPosition(this.header.rec_start);
        for (int i = 0; i < records.length; ++i) {
            try {
                final ARZRecord rec = new ARZRecord();
                rec.strID = buffer.getInt();
                rec.len_str = buffer.getInt();
                rec.str = buffer.getString(rec.len_str);
                rec.offset = buffer.getInt();
                rec.len_comp = buffer.getInt();
                rec.len_decomp = buffer.getInt();
                rec.filedata = buffer.getBytes8();
                records[i] = rec;
            } catch (Exception ex) {
                GDMsgLogger.addError(ex);
                records[i] = null;
            }
        }
        return records;
    }

    private void extractRecords(final GDBuffer buffer, final boolean extractItems) {
        final NumberFormat formatter = new DecimalFormat("#0.000000");
        final LZ4Factory factory = LZ4Factory.fastestInstance();
        final LZ4FastDecompressor decomp = factory.fastDecompressor();
        String attrib = null;
        String value = null;
        for (int i = 0; i < this.records.length; ++i) {
            try {
                if (this.records[i] != null) {
                    this.records[i].setFileName(this.strings[this.records[i].strID].str);
                    if (this.records[i].error) {
                        this.records[i] = null;
                    } else if (!ARZRecord.processDir(this.records[i].getFileName())) {
                        this.records[i] = null;
                    } else {
                        this.records[i].storeInDB = true;
                        final byte[] bComp = buffer.getByteArray(this.records[i].offset + 24, this.records[i].len_comp);
                        final byte[] bDecomp = new byte[this.records[i].len_decomp];
                        decomp.decompress(bComp, bDecomp);
                        int offset = 0;
                        value = "";
                        while (offset < bDecomp.length) {
                            final int typeOffset = offset;
                            final short varType = GDReader.getUShort(bDecomp, offset);
                            offset += 2;
                            final short count = GDReader.getUShort(bDecomp, offset);
                            offset += 2;
                            final int strIdx = GDReader.getUInt(bDecomp, offset);
                            offset += 4;
                            for (int j = 0; j < count; ++j) {
                                switch (varType) {
                                    case 0: {
                                        final int valInt = GDReader.getInt(bDecomp, offset);
                                        value = String.valueOf(valInt);
                                        break;
                                    }
                                    case 1: {
                                        final float valFloat = GDReader.getFloat(bDecomp, offset);
                                        value = formatter.format(valFloat);
                                        break;
                                    }
                                    case 2: {
                                        final int valStrIdx = GDReader.getUInt(bDecomp, offset);
                                        value = this.strings[valStrIdx].str;
                                        break;
                                    }
                                    case 3: {
                                        final boolean valBool = GDReader.getBool(bDecomp, offset);
                                        if (valBool) {
                                            value = "1";
                                            break;
                                        }
                                        value = "0";
                                        break;
                                    }
                                    default: {
                                        final Object[] args = {this.records[i].getFileName(), this.strings[strIdx].str};
                                        final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_UNKNOWN_VAR_TYPE", args);
                                        throw new GDParseException(msg, typeOffset);
                                    }
                                }
                                offset += 4;
                                attrib = this.strings[strIdx].str;
                                if (attrib.equals("templateName")) {
                                    if (!ARZRecord.processTemplate(value, extractItems)) {
                                        this.records[i] = null;
                                        break;
                                    }
                                    if (!ARZRecord.processFile(this.records[i].getFileName(), value)) {
                                        this.records[i] = null;
                                        break;
                                    }
                                }
                                this.fillAttrib(attrib, i, value, j);
                            }
                            if (this.records[i] == null) {
                                break;
                            }
                        }
                        if (this.records[i] != null) {
                            if (this.records[i].getTemplate() == null) {
                                this.records[i] = null;
                            } else if (ARZFormulaSetPool.isFormula(this.records[i].getTemplate())) {
                                ARZFormulaSetPool.storeFormulaSet(this.records[i]);
                            }
                        }
                    }
                }
            } catch (Exception ex) {
                final Object[] args2 = {this.records[i].getFileName()};
                final String msg2 = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_IN_ENTRY", args2);
                GDMsgLogger.addError(msg2);
                GDMsgLogger.addError(ex);
                this.records[i] = null;
            }
        }
    }

    private static int parseInt(final String s) {
        int pos = s.indexOf(".");
        if (pos == -1) {
            pos = s.indexOf(",");
        }
        int val = 0;
        if (pos == -1) {
            try {
                val = Integer.parseInt(s);
            } catch (NumberFormatException ex) {
                val = -1;
            }
        } else {
            val = (int) parseFloat(s);
        }
        return val;
    }

    private static float parseFloat(String s) {
        final int pos = s.indexOf(",");
        if (pos != -1) {
            s = s.substring(0, pos) + "." + s.substring(pos + 1);
        }
        float val = 0.0f;
        try {
            val = Float.parseFloat(s);
        } catch (NumberFormatException ex) {
            val = -1.0f;
        }
        return val;
    }

    private static void logTag(final String attrib, final int value, final ARZRecord record) {
        if (value == 0) {
            return;
        }
        if (!attrib.startsWith("character") && !attrib.startsWith("defensive") && !attrib.startsWith("offensive") && !attrib.startsWith("retaliation")) {
            return;
        }
        if (attrib.equals("characterBaseAttackSpeedTag") || attrib.equals("characterAttributeEquations") || attrib.equals("characterGenderProfile") || attrib.equals("characterRacialProfile") || attrib.equals("characterRunSpeed") || attrib.equals("characterRunSpeedJitter") || attrib.equals("characterSpellCastSpeed") || attrib.equals("defensiveAbilityDamageFxPak") || attrib.equals("defensiveManaBurn") || attrib.equals("defensiveReductionDamageFxPak") || attrib.equals("offensiveAbilityDamageFxPak") || attrib.equals("offensiveReductionDamageFxPak")) {
            return;
        }
        final Object[] args = {attrib};
        final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_TAG_UNKNOWN", args);
        GDStashFrame.messageToList(msg);
    }

    private boolean fillAttribAffix(final String attrib, final int pos, final String value) {
        if (attrib.equals("lootRandomizerCost")) {
            int iVal = 0;
            try {
                iVal = Integer.parseInt(value);
            } catch (NumberFormatException ex) {
                iVal = 0;
                final Object[] args = {this.records[pos].getFileName(), attrib, value};
                final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_TAG_INVALID_VALUE", args);
                GDMsgLogger.addError(msg);
            }
            this.records[pos].setLootRandomCost(iVal);
            return true;
        }
        if (attrib.equals("lootRandomizerJitter")) {
            int iVal = 0;
            try {
                iVal = (int) parseFloat(value);
            } catch (NumberFormatException ex) {
                iVal = 0;
                final Object[] args = {this.records[pos].getFileName(), attrib, value};
                final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_TAG_INVALID_VALUE", args);
                GDMsgLogger.addError(msg);
            }
            this.records[pos].setRNGPercent(iVal);
            return true;
        }
        if (attrib.equals("lootRandomizerName")) {
            this.records[pos].setLootRandomName(value);
            return true;
        }
        return false;
    }

    private boolean fillAttribAffixSet(final String attrib, final int pos, final String value) {
        if (attrib.startsWith("randomizerLevelMax")) {
            final String s = attrib.substring(18);
            final int i = parseInt(s);
            final int level = parseInt(value);
            this.records[pos].addRandomizerMaxLevelEntry(i, level);
            return true;
        }
        if (attrib.startsWith("randomizerLevelMin")) {
            final String s = attrib.substring(18);
            final int i = parseInt(s);
            final int level = parseInt(value);
            this.records[pos].addRandomizerMinLevelEntry(i, level);
            return true;
        }
        if (attrib.startsWith("randomizerName")) {
            final String s = attrib.substring(14);
            final int i = parseInt(s);
            this.records[pos].addRandomizerAffixIDEntry(i, value);
            return true;
        }
        return false;
    }

    public static int getGenderCode(final String s) {
        int code = -1;
        if (s.equals("[ms]")) {
            code = 0;
        }
        if (s.equals("[mp]")) {
            code = 3;
        }
        if (s.equals("[fs]")) {
            code = 1;
        }
        if (s.equals("[fp]")) {
            code = 4;
        }
        if (s.equals("[ns]")) {
            code = 2;
        }
        if (s.equals("[np]")) {
            code = 5;
        }
        return code;
    }

    private boolean fillAttribSkillModifier(final String attrib, final int pos, final String value, final int index) {
        if (attrib.startsWith("modifiedSkillName")) {
            final String s = attrib.substring(17);
            final int i = parseInt(s);
            this.records[pos].addModifierSkillID(i, value);
            return true;
        }
        if (attrib.startsWith("modifierSkillName")) {
            final String s = attrib.substring(17);
            final int i = parseInt(s);
            this.records[pos].addModifierModifierID(i, value);
            return true;
        }
        if (attrib.equals("itemSkillModifierControl")) {
            final int iVal = parseInt(value);
            this.records[pos].setItemSetSkillModifierLevel(iVal, index);
        }
        return false;
    }

    private boolean fillAttribStat(final String attrib, final int pos, final String value, final int index) {
        boolean processed = false;
        if (attrib.startsWith("defensive")) {
            processed = this.fillAttribStatDefense(attrib, pos, value, index);
            if (processed) {
                return true;
            }
        }
        if (attrib.startsWith("offensive")) {
            processed = this.fillAttribStatOffense(attrib, pos, value, index);
            if (processed) {
                return true;
            }
        }
        if (attrib.startsWith("retaliation")) {
            processed = this.fillAttribStatRetaliation(attrib, pos, value, index);
            if (processed) {
                return true;
            }
        }
        processed = this.fillAttribStatChar(attrib, pos, value, index);
        return processed;
    }

    private boolean fillAttribStatDetails(final String attrib, final String search, final int pos, final String value, final int index) {
        boolean processed = false;
        final int len = search.length();
        int p = attrib.indexOf(search);
        if (p == -1) {
            if (search.equals("retaliationPercentCurrentLife")) {
                p = attrib.indexOf("retaliationPercentcurrentLife");
            }
            if (p == -1) {
                return false;
            }
        }
        final String suf = attrib.substring(p + len);
        final DBStat stat = this.records[pos].getCreateDBStat(search, index);
        final float fVal = parseFloat(value);
        final int iVal = (int) fVal;
        if (suf.equals("Global")) {
            stat.setGlobal(iVal > 0);
            processed = true;
        }
        if (suf.equals("XOR")) {
            stat.setXOR(iVal > 0);
            processed = true;
        }
        if (suf.equals("")) {
            stat.setStatMin(fVal);
            processed = true;
        }
        if (suf.equals("Min")) {
            stat.setStatMin(fVal);
            processed = true;
        }
        if (suf.equals("Max")) {
            stat.setStatMax(fVal);
            processed = true;
        }
        if (suf.equals("Chance")) {
            stat.setStatChance(iVal);
            processed = true;
        }
        if (suf.equals("Modifier")) {
            stat.setStatModifier(iVal);
            processed = true;
        }
        if (suf.equals("ModifierChance")) {
            stat.setStatModifierChance(iVal);
            processed = true;
        }
        if (suf.equals("Duration")) {
            stat.setMinDuration(iVal);
            processed = true;
        }
        if (suf.equals("DurationMin")) {
            stat.setMinDuration(iVal);
            processed = true;
        }
        if (suf.equals("DurationMax")) {
            stat.setMaxDuration(iVal);
            processed = true;
        }
        if (suf.equals("DurationChance")) {
            stat.setDurationChance(iVal);
            processed = true;
        }
        if (suf.equals("DurationModifier")) {
            stat.setDurationModifier(iVal);
            processed = true;
        }
        if (suf.equals("DurationModifierChance")) {
            stat.setDurationModifierChance(iVal);
            processed = true;
        }
        if (suf.equals("MaxResist")) {
            stat.setMaxResist(iVal);
            processed = true;
        }
        return processed;
    }

    private boolean fillAttribStatChar(final String attrib, final int pos, final String value, final int index) {
        boolean processed = false;
        processed = this.fillAttribStatDetails(attrib, "skillManaCost", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "skillCooldownTime", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "skillActiveDuration", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "lifeMonitorPercent", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "weaponDamagePct", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "damageAbsorptionPercent", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "skillTargetRadius", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "petBurstSpawn", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "petLimit", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "skillMaxLevel", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "sparkMaxNumber", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "skillTargetNumber", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterLightRadius", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterDefensiveAbility", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterOffensiveAbility", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterMana", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterManaLimitReserve", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterManaLimitReserveReduction", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterManaRegen", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterHealIncreasePercent", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterLife", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterLifeRegen", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterConstitution", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "skillLifeBonus", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "skillLifePercent", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterDexterity", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterStrength", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterIntelligence", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterAttackSpeed", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterSpellCastSpeed", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterRunSpeed", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterTotalSpeed", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "blockRecoveryTime", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterDefensiveBlockRecoveryReduction", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterGlobalReqReduction", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterEnergyAbsorptionPercent", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterIncreasedExperience", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "skillCooldownReduction", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "skillManaCostReduction", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "racialBonusPercentDamage", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "piercingProjectile", pos, value, index);
        if (processed) {
            return processed;
        }
        if (attrib.equals("racialBonusRace")) {
            String tag = value;
            if (!tag.startsWith("tag")) {
                tag = "tag" + tag;
            }
            final String name = GDStashFrame.arcList.getTag(ARCDecompress.FileModule.All, GDConstants.TAG_TEXT_CREATURES, tag, false);
            this.records[pos].addRace(value, name);
            return true;
        }
        processed = this.fillAttribStatDetails(attrib, "characterDeflectProjectile", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterDodgePercent", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterLevelReqReduction", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterArmorStrengthReqReduction", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterHuntingDexterityReqReduction", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterMeleeDexterityReqReduction", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterMeleeStrengthReqReduction", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterWeaponStrengthReqReduction", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterWeaponIntelligenceReqReduction", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterJewelryIntelligenceReqReduction", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "characterShieldStrengthReqReduction", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "conversionPercentage", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "conversionPercentage2", pos, value, index);
        if (processed) {
            return processed;
        }
        if (!processed) {
            final int i = parseInt(value);
            logTag(attrib, i, this.records[pos]);
        }
        return processed;
    }

    private boolean fillAttribStatDefense(final String attrib, final int pos, final String value, final int index) {
        boolean processed = false;
        processed = this.fillAttribStatDetails(attrib, "defensiveAbsorption", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveAether", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveAll", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveBleeding", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveBlock", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveBlockAmount", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveBonusProtection", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveChaos", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveCold", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveConfusion", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveConvert", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveDisruption", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveElemental", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveElementalResistance", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveFear", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveFire", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveFreeze", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveKnockdown", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveLife", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveLightning", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensivePercentCurrentLife", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensivePercentReflectionResistance", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveManaBurnRatio", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensivePetrify", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensivePhysical", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensivePierce", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensivePoison", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveProtection", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveReflect", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveSleep", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveSlowLifeLeach", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveSlowManaLeach", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveStun", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveTaunt", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveTotalSpeedResistance", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "defensiveTrap", pos, value, index);
        if (processed) {
            return processed;
        }
        if (!processed) {
            final int i = parseInt(value);
            logTag(attrib, i, this.records[pos]);
        }
        return processed;
    }

    private boolean fillAttribStatOffense(final String attrib, final int pos, final String value, final int index) {
        boolean processed = false;
        processed = this.fillAttribStatDetails(attrib, "offensiveAether", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveBaseAether", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveBaseChaos", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveBaseCold", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveBaseFire", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveBaseLife", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveBaseLightning", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveBasePoison", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveBonusPhysical", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveChaos", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveCold", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveConfusion", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveConvert", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveCritDamage", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveDamageMult", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveDisruption", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveElemental", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveElementalReductionPercent", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveElementalResistanceReductionAbsolute", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveElementalResistanceReductionPercent", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveFear", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveFire", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveFreeze", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveFumble", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveKnockdown", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveLife", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveLifeLeech", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveLightning", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensivePercentCurrentLife", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveManaBurnDamageRatio", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveManaBurnDrain", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensivePetrify", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensivePhysical", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensivePhysicalReductionPercent", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensivePhysicalResistanceReductionAbsolute", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensivePhysicalResistanceReductionPercent", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensivePierce", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensivePierceRatio", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensivePoison", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveProjectileFumble", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveSleep", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveSlowAttackSpeed", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveSlowBleeding", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveSlowCold", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveSlowDefensiveAbility", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveSlowDefensiveReduction", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveSlowFire", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveSlowLife", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveSlowLifeLeach", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveSlowLightning", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveSlowManaLeach", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveSlowOffensiveAbility", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveSlowOffensiveReduction", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveSlowPhysical", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveSlowPoison", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveSlowRunSpeed", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveSlowTotalSpeed", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveStun", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveTaunt", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveTotalDamage", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveTotalDamageReductionPercent", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveTotalResistanceReductionAbsolute", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveTotalResistanceReductionPercent", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "offensiveTrap", pos, value, index);
        if (processed) {
            return processed;
        }
        if (!processed) {
            final int i = parseInt(value);
            logTag(attrib, i, this.records[pos]);
        }
        return processed;
    }

    private boolean fillAttribStatRetaliation(final String attrib, final int pos, final String value, final int index) {
        boolean processed = false;
        processed = this.fillAttribStatDetails(attrib, "retaliationAether", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationChaos", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationCold", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationConfusion", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationConvert", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationDamagePct", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationElemental", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationFear", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationFire", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationFreeze", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationLife", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationLightning", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationPercentCurrentLife", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationPetrify", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationPhysical", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationPierce", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationPierceRatio", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationPoison", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationSleep", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationSlowAttackSpeed", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationSlowBleeding", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationSlowCold", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationSlowDefensiveAbility", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationSlowFire", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationSlowLife", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationSlowLifeLeach", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationSlowLightning", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationSlowManaLeach", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationSlowOffensiveAbility", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationSlowOffensiveReduction", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationSlowPhysical", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationSlowPoison", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationSlowRunSpeed", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationStun", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationTotalDamage", pos, value, index);
        if (processed) {
            return processed;
        }
        processed = this.fillAttribStatDetails(attrib, "retaliationTrap", pos, value, index);
        if (processed) {
            return processed;
        }
        if (!processed) {
            final int i = parseInt(value);
            logTag(attrib, i, this.records[pos]);
        }
        return processed;
    }

    public static String[] getGenderTexts(final String text) {
        final String[] genders = new String[6];
        if (text == null) {
            return genders;
        }
        String remainder = text;
        String gender = null;
        String value = null;
        int code = -1;
        if (remainder.startsWith("|")) {
            remainder = remainder.substring(2);
        }
        if (remainder.startsWith("$")) {
            remainder = remainder.substring(1);
        }
        while (remainder != null) {
            int pos = remainder.indexOf("[");
            if (pos != -1) {
                gender = remainder.substring(pos, pos + 4);
                remainder = remainder.substring(pos + 4);
                pos = remainder.indexOf("[");
                if (pos != -1) {
                    value = remainder.substring(0, pos);
                    remainder = remainder.substring(pos);
                } else {
                    value = remainder;
                    remainder = null;
                }
                code = getGenderCode(gender);
                if (code == -1) {
                    code = 0;
                }
                genders[code] = value;
            } else {
                value = remainder;
                remainder = null;
                genders[1] = (genders[0] = value);
                genders[3] = (genders[2] = value);
                genders[5] = (genders[4] = value);
            }
        }
        return genders;
    }

    private boolean fillEngineGame(final String attrib, final int pos, final String value, final int index) {
        int i = 0;
        boolean error = false;
        try {
            i = parseInt(value);
        } catch (NumberFormatException ex) {
            i = 0;
            error = true;
        }
        if (attrib.equals("factionAlternateNeutralTag")) {
            this.records[pos].setFactionAltNeutralTag(value);
            return true;
        }
        if (attrib.startsWith("factionValue")) {
            final String s = attrib.substring(12);
            final int idx = parseInt(s);
            this.records[pos].addFactionReputationValue(idx, i);
            return true;
        }
        if (attrib.startsWith("factionTag")) {
            final String s = attrib.substring(10);
            final int idx = parseInt(s);
            this.records[pos].addFactionReputationStateTag(idx, value);
            return true;
        }
        if (attrib.equals("skillMasteryTierLevel")) {
            this.records[pos].addMasteryTier(index, i);
            return true;
        }
        return false;
    }

    private boolean fillFaction(final String attrib, final int pos, final String value) {
        if (attrib.equals("bountyEnabled")) {
            this.records[pos].setFactionBountyEnabled(value.equals("1"));
            return true;
        }
        if (attrib.startsWith("questEnabled")) {
            this.records[pos].setFactionQuestEnabled(value.equals("1"));
            return true;
        }
        if (attrib.startsWith("myFaction")) {
            this.records[pos].setFactionTag(value);
            return true;
        }
        return false;
    }

    private boolean fillMerchant(final String attrib, final int pos, final String value) {
        if (attrib.equals("factions")) {
            this.records[pos].setMerchantFactionID(value);
            return true;
        }
        if (attrib.startsWith("marketFileName")) {
            this.records[pos].setMerchantTableSetID(value);
            return true;
        }
        if (attrib.startsWith("friendlyNormalTable")) {
            this.records[pos].addMerchantTableSetTableID(value);
            return true;
        }
        if (attrib.startsWith("respectedNormalTable")) {
            this.records[pos].addMerchantTableSetTableID(value);
            return true;
        }
        if (attrib.startsWith("honoredNormalTable")) {
            this.records[pos].addMerchantTableSetTableID(value);
            return true;
        }
        if (attrib.startsWith("reveredNormalTable")) {
            this.records[pos].addMerchantTableSetTableID(value);
            return true;
        }
        if (attrib.startsWith("marketStaticItems")) {
            this.records[pos].addMerchantTableItemID(value);
            return true;
        }
        return false;
    }

    public static void convertTextures(final String dir) {
        try {
            final File file = new File(dir);
            if (!file.exists()) {
                return;
            }
            if (file.isDirectory()) {
                final File[] files = file.listFiles();
                for (int i = 0; i < files.length; ++i) {
                    convertTextures(files[i].getCanonicalPath());
                }
            } else {
                final String fn = file.getCanonicalPath();
                try {
                    if (fn.endsWith(".tex")) {
                        final String pngName = fn.substring(0, fn.length() - 4) + ".png";
                        BufferedImage image = null;
                        try {
                            image = DDSLoader.load(fn);
                        } catch (Exception ex) {
                            image = null;
                        }
                        if (image != null) {
                            final File fImg = new File(pngName);
                            ImageIO.write(image, "PNG", fImg);
                        }
                    }
                } catch (IOException ex2) {
                }
            }
        } catch (Exception ex3) {
        }
    }

    private void fillAttrib(final String attrib, final int pos, final String value, final int index) throws GDParseException {
        if (attrib.equals("templateName")) {
            this.records[pos].setTemplate(value);
            return;
        }
        if (attrib.equals("Class")) {
            this.records[pos].setRecordClass(value);
            return;
        }
        if (attrib.equals("FileDescription")) {
            this.records[pos].setFileDescription(value);
            return;
        }
        if (attrib.equals("conversionInType")) {
            this.records[pos].setConversionIn(value);
            return;
        }
        if (attrib.equals("conversionInType2")) {
            this.records[pos].setConversionIn2(value);
            return;
        }
        if (attrib.equals("conversionOutType")) {
            this.records[pos].setConversionOut(value);
            return;
        }
        if (attrib.equals("conversionOutType2")) {
            this.records[pos].setConversionOut2(value);
            return;
        }
        if (attrib.equals("dlcRequirement")) {
            this.records[pos].setDLCRequirement(value);
            return;
        }
        if (attrib.equals("itemClassification")) {
            this.records[pos].setRarity(value);
            return;
        }
        if (!this.records[pos].isItemSet() && attrib.equals("itemSkillName")) {
            this.records[pos].setItemSkillID(value);
            return;
        }
        if (attrib.equals("itemSkillLevelEq")) {
            int level = parseInt(value);
            if (level == -1) {
                level = 1;
                this.records[pos].setItemSkillLevelFormula(value);
            }
            this.records[pos].setItemSkillLevel(level);
            return;
        }
        if (attrib.equals("itemSkillAutoController")) {
            this.records[pos].setSkillControllerID(value);
            return;
        }
        if (attrib.equals("levelRequirement")) {
            final int level = parseInt(value);
            this.records[pos].setRequiredLevel(level);
            return;
        }
        if (attrib.equals("offensiveGlobalChance")) {
            final int chance = parseInt(value);
            this.records[pos].setOffensiveChance(chance);
            return;
        }
        if (attrib.equals("petBonusName")) {
            this.records[pos].setPetBonusID(value);
            return;
        }
        if (attrib.equals("retaliationGlobalChance")) {
            final int chance = parseInt(value);
            this.records[pos].setRetaliationChance(chance);
            return;
        }
        if (this.fillAttribSkillModifier(attrib, pos, value, index)) {
            return;
        }
        boolean processed = false;
        if (this.records[pos].isGameEngine()) {
            processed = this.fillEngineGame(attrib, pos, value, index);
            if (processed) {
                return;
            }
        }
        if (this.records[pos].isFaction()) {
            processed = this.fillFaction(attrib, pos, value);
            if (processed) {
                return;
            }
        }
        if (this.records[pos].isMerchant() || this.records[pos].isMerchantTableSet() || this.records[pos].isMerchantTable()) {
            processed = this.fillMerchant(attrib, pos, value);
            if (processed) {
                return;
            }
        }
        if (this.records[pos].isPlayerEngine()) {
            processed = this.fillEnginePlayer(attrib, pos, value, index);
            if (processed) {
                return;
            }
        }
        if (this.records[pos].isConstellation() || this.records[pos].isSkillButton()) {
            processed = this.fillAttribConstellation(attrib, pos, value);
            if (processed) {
                return;
            }
        }
        if (this.records[pos].isBitmap()) {
            processed = this.fillAttribBitmap(attrib, pos, value);
            if (processed) {
                return;
            }
        }
        if (this.records[pos].isInventoryGrid()) {
            processed = this.fillAttribInventoryGrid(attrib, pos, value);
            if (processed) {
                return;
            }
        }
        if (this.records[pos].isCaravanWindow()) {
            processed = this.fillAttribCaravanWindow(attrib, pos, value);
            if (processed) {
                return;
            }
        }
        if (this.records[pos].isClassTable()) {
            processed = this.fillAttribClassTable(attrib, pos, value);
            if (processed) {
                return;
            }
        }
        if (this.records[pos].isSkillMaster()) {
            processed = this.fillAttribSkillMaster(attrib, pos, value);
            if (processed) {
                return;
            }
        }
        if (this.records[pos].isShrine()) {
            processed = this.fillAttribShrine(attrib, pos, value);
            if (processed) {
                return;
            }
        }
        if (this.records[pos].isSkillTree()) {
            processed = this.fillAttribSkillTree(attrib, pos, value);
            if (processed) {
                return;
            }
        }
        if (this.records[pos].isSkill()) {
            processed = this.fillAttribSkill(attrib, pos, value, index);
            if (processed) {
                return;
            }
        }
        if (this.records[pos].isPet()) {
            processed = this.fillAttribPet(attrib, pos, value, index);
            if (processed) {
                return;
            }
        }
        if (this.records[pos].isPetBio()) {
            processed = this.fillAttribPetBio(attrib, pos, value, index);
            if (processed) {
                return;
            }
        }
        if (this.records[pos].isController()) {
            processed = this.fillAttribController(attrib, pos, value);
            if (processed) {
                return;
            }
        }
        if (this.records[pos].isAffix()) {
            processed = this.fillAttribAffix(attrib, pos, value);
            if (processed) {
                return;
            }
        }
        if (this.records[pos].isAffixSet()) {
            processed = this.fillAttribAffixSet(attrib, pos, value);
            if (processed) {
                return;
            }
        }
        if (this.records[pos].isItemSet()) {
            processed = this.fillAttribItemSet(attrib, pos, value);
            if (processed) {
                return;
            }
        }
        if (this.records[pos].isLootTable()) {
            processed = this.fillAttribLootTable(attrib, pos, value);
            if (processed) {
                return;
            }
        }
        if (this.records[pos].isLootTableSet()) {
            processed = this.fillAttribLootTableSet(attrib, pos, value);
            if (processed) {
                return;
            }
        }
        if (this.records[pos].isFormulaSet()) {
            processed = this.fillAttribFormula(attrib, pos, value);
            if (processed) {
                return;
            }
        }
        processed = this.fillAttribItem(attrib, pos, value);
        if (processed) {
            return;
        }
        processed = this.fillAttribStat(attrib, pos, value, index);
        if (processed) {
            return;
        }
        processed = this.fillAttribSkillBonus(attrib, pos, value, index);
        if (processed) {
            return;
        }
    }

    private boolean fillAttribItem(final String attrib, final int pos, final String value) {
        if (attrib.equals("amulet")) {
            this.records[pos].setSlotAmulet(value.equals("1"));
            return true;
        }
        if (attrib.equals("armorClassification")) {
            this.records[pos].setArmorClass(value);
            return true;
        }
        if (attrib.equals("artifactClassification")) {
            this.records[pos].setArtifactClass(value);
            return true;
        }
        if (attrib.equals("artifactName") || attrib.equals("forcedRandomArtifactName")) {
            if (value == null) {
                return true;
            }
            if (value.isEmpty()) {
                return true;
            }
            if (value.contains("loottable")) {
                return true;
            }
            this.records[pos].setArtifactID(value);
            return true;
        } else {
            if (attrib.equals("attributeScalePercent")) {
                int iVal = 0;
                try {
                    iVal = (int) parseFloat(value);
                } catch (NumberFormatException ex) {
                    iVal = 0;
                    final Object[] args = {this.records[pos].getFileName(), attrib, value};
                    final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_TAG_INVALID_VALUE", args);
                    GDMsgLogger.addError(msg);
                }
                this.records[pos].setRNGPercent(iVal);
                return true;
            }
            if (!this.records[pos].isItemSet() && attrib.equals("augmentAllLevel")) {
                final int iVal = parseInt(value);
                this.records[pos].setPlusAllSkills(iVal);
                return true;
            }
            if (attrib.equals("axe")) {
                this.records[pos].setSlotAxe1H(value.equals("1"));
                return true;
            }
            if (attrib.equals("axe2h")) {
                this.records[pos].setSlotAxe2H(value.equals("1"));
                return true;
            }
            if (attrib.equals("baseTexture")) {
                this.records[pos].setBaseTextureID(value);
                return true;
            }
            if (attrib.equals("baseTextures")) {
                this.records[pos].addBaseTextureID(value);
                return true;
            }
            if (attrib.equals("bumpTexture")) {
                this.records[pos].setBumpTextureID(value);
                return true;
            }
            if (attrib.equals("bumpTextures")) {
                this.records[pos].addBumpTextureID(value);
                return true;
            }
            if (attrib.equals("glowTexture")) {
                this.records[pos].setGlowTextureID(value);
                return true;
            }
            if (attrib.equals("glowTextures")) {
                this.records[pos].addGlowTextureID(value);
                return true;
            }
            if (attrib.equals("shader")) {
                this.records[pos].setShaderID(value);
                return true;
            }
            if (attrib.equals("bitmap") || attrib.equals("artifactBitmap") || attrib.equals("artifactFormulaBitmapName") || attrib.equals("noteBitmap") || attrib.equals("relicBitmap") || attrib.equals("emptyBitmap") || attrib.equals("fullBitmap")) {
                this.records[pos].setBitmapID(value);
                return true;
            }
            if (attrib.equals("bonusTableName")) {
                this.records[pos].setBonusAffixSetID(value);
            }
            if (attrib.equals("cannotPickUp")) {
                this.records[pos].setCannotPickup(value.equals("1"));
                return true;
            }
            if (attrib.equals("chest")) {
                this.records[pos].setSlotChest(value.equals("1"));
                return true;
            }
            if (attrib.equals("completedRelicLevel")) {
                final int iVal = parseInt(value);
                this.records[pos].setComponentPieces(iVal);
                return true;
            }
            if (attrib.equals("dagger")) {
                this.records[pos].setSlotDagger1H(value.equals("1"));
                return true;
            }
            if (attrib.equals("feet")) {
                this.records[pos].setSlotFeet(value.equals("1"));
                return true;
            }
            if (attrib.equals("hands")) {
                this.records[pos].setSlotHands(value.equals("1"));
                return true;
            }
            if (attrib.equals("head")) {
                this.records[pos].setSlotHead(value.equals("1"));
                return true;
            }
            if (attrib.equals("hidePrefixName")) {
                this.records[pos].setHidePrefix(value.equals("1"));
                return true;
            }
            if (attrib.equals("hideSuffixName")) {
                this.records[pos].setHideSuffix(value.equals("1"));
                return true;
            }
            if (attrib.equals("itemCostName")) {
                this.records[pos].setCostFormulaSetID(value);
                return true;
            }
            if (attrib.equals("itemLevel")) {
                final int iVal = parseInt(value);
                this.records[pos].setItemLevel(iVal);
                return true;
            }
            if (attrib.equals("itemNameTag") || attrib.equals("description")) {
                if (value != null && !value.equals("")) {
                    this.records[pos].setItemNameTag(value);
                }
                return true;
            }
            if (attrib.equals("itemQualityTag")) {
                this.records[pos].setQualityTag(value);
                return true;
            }
            if (attrib.equals("itemSetName")) {
                this.records[pos].setItemSetID(value);
                return true;
            }
            if (attrib.equals("itemStyleTag")) {
                this.records[pos].setStyleTag(value);
                return true;
            }
            if (attrib.equals("itemText")) {
                this.records[pos].setItemDescriptionTag(value);
                return true;
            }
            if (attrib.equals("legs")) {
                this.records[pos].setSlotLegs(value.equals("1"));
                return true;
            }
            if (attrib.equals("mace")) {
                this.records[pos].setSlotMace1H(value.equals("1"));
                return true;
            }
            if (attrib.equals("mace2h")) {
                this.records[pos].setSlotMace2H(value.equals("1"));
                return true;
            }
            if (attrib.equals("maxStackSize")) {
                final int iVal = parseInt(value);
                this.records[pos].setMaxStackSize(iVal);
                return true;
            }
            if (attrib.equals("medal")) {
                this.records[pos].setSlotMedal(value.equals("1"));
                return true;
            }
            if (attrib.equals("mesh")) {
                this.records[pos].setMeshID(value);
                return true;
            }
            if (attrib.equals("offhand")) {
                this.records[pos].setSlotOffhand(value.equals("1"));
                return true;
            }
            if (attrib.equals("quest")) {
                this.records[pos].setQuestItem(value.equals("1"));
                return true;
            }
            if (attrib.equals("ranged1h")) {
                this.records[pos].setSlotRanged1H(value.equals("1"));
                return true;
            }
            if (attrib.equals("ranged2h")) {
                this.records[pos].setSlotRanged2H(value.equals("1"));
                return true;
            }
            if (attrib.equals("ring")) {
                this.records[pos].setSlotRing(value.equals("1"));
                return true;
            }
            if (attrib.equals("scepter")) {
                this.records[pos].setSlotScepter1H(value.equals("1"));
                return true;
            }
            if (attrib.equals("shardBitmap")) {
                this.records[pos].setShardBitmapID(value);
                return true;
            }
            if (attrib.equals("shield")) {
                this.records[pos].setSlotShield(value.equals("1"));
                return true;
            }
            if (attrib.equals("shoulders")) {
                this.records[pos].setSlotShoulders(value.equals("1"));
                return true;
            }
            if (attrib.equals("soulbound")) {
                this.records[pos].setSoulbound(value.equals("1"));
                return true;
            }
            if (attrib.equals("spear")) {
                this.records[pos].setSlotSpear1H(value.equals("1"));
                return true;
            }
            if (attrib.equals("spear2h")) {
                this.records[pos].setSlotSpear2H(value.equals("1"));
                return true;
            }
            if (attrib.equals("staff")) {
                this.records[pos].setSlotStaff2H(value.equals("1"));
                return true;
            }
            if (attrib.equals("sword")) {
                this.records[pos].setSlotSword1H(value.equals("1"));
                return true;
            }
            if (attrib.equals("sword2h")) {
                this.records[pos].setSlotSword2H(value.equals("1"));
                return true;
            }
            if (attrib.equals("waist")) {
                this.records[pos].setSlotBelt(value.equals("1"));
                return true;
            }
            if (attrib.equals("skillName")) {
                this.records[pos].setItemSkillID(value);
                return true;
            }
            return false;
        }
    }

    private boolean fillAttribConstellation(final String attrib, final int pos, final String value) {
        int i = 0;
        boolean error = false;
        try {
            i = parseInt(value);
        } catch (NumberFormatException ex) {
            i = 0;
            error = true;
        }
        if (attrib.equals("constellationDisplayTag")) {
            this.records[pos].setConstellationNameTag(value);
            return true;
        }
        if (attrib.equals("constellationInfoTag")) {
            this.records[pos].getConstellationInfoTag(value);
            return true;
        }
        if (attrib.startsWith("affinityGivenName")) {
            this.records[pos].addConstellationAffinityName(attrib, value);
            return true;
        }
        if (attrib.startsWith("affinityRequiredName")) {
            this.records[pos].addConstellationAffinityName(attrib, value);
            return true;
        }
        if (attrib.startsWith("affinityGiven")) {
            this.records[pos].addConstellationAffinityPoints(attrib, i);
            return true;
        }
        if (attrib.startsWith("affinityRequired")) {
            this.records[pos].addConstellationAffinityPoints(attrib, i);
            return true;
        }
        if (attrib.startsWith("devotionButton")) {
            this.records[pos].addConstellationStar(attrib, value);
            return true;
        }
        if (attrib.equals("skillName")) {
            this.records[pos].setButtonSkillID(value);
            return true;
        }
        if (attrib.equals("bitmapPositionX")) {
            this.records[pos].setPosX(i);
            return true;
        }
        if (attrib.equals("bitmapPositionY")) {
            this.records[pos].setPosY(i);
            return true;
        }
        if (attrib.equals("skillOffsetX")) {
            this.records[pos].setOffsetX(i);
            return true;
        }
        if (attrib.equals("skillOffsetY")) {
            this.records[pos].setOffsetY(i);
            return true;
        }
        if (attrib.equals("isCircular")) {
            this.records[pos].setCircularButton(value.equals("1"));
            return true;
        }
        return false;
    }

    private boolean fillAttribBitmap(final String attrib, final int pos, final String value) {
        int i = 0;
        boolean error = false;
        try {
            i = parseInt(value);
        } catch (NumberFormatException ex) {
            i = 0;
            error = true;
        }
        if (attrib.equals("bitmapName") || attrib.equals("bitmapFullName")) {
            this.records[pos].setBitmapID(value);
            return true;
        }
        if (attrib.equals("bitmapPositionX")) {
            this.records[pos].setPosX(i);
            return true;
        }
        if (attrib.equals("bitmapPositionY")) {
            this.records[pos].setPosY(i);
            return true;
        }
        return false;
    }

    private boolean fillAttribClassTable(final String attrib, final int pos, final String value) {
        int i = 0;
        boolean error = false;
        try {
            i = parseInt(value);
        } catch (NumberFormatException ex) {
            i = 0;
            error = true;
        }
        if (attrib.equals("masteryBar")) {
            this.records[pos].setMasteryBarID(value);
            return true;
        }
        if (attrib.equals("skillPaneBaseBitmap")) {
            this.records[pos].setSkillPaneID(value);
            return true;
        }
        if (attrib.equals("skillPaneMasteryBitmap")) {
            this.records[pos].setMasteryBitmapID(value);
            return true;
        }
        if (attrib.equals("skillTabTitle")) {
            this.records[pos].setTitleTag(value);
            return true;
        }
        if (attrib.equals("tabSkillButtons")) {
            this.records[pos].addSkillButton(value);
            return true;
        }
        return false;
    }

    private boolean fillAttribSkillMaster(final String attrib, final int pos, final String value) {
        if (attrib.startsWith("skillCtrlPane")) {
            this.records[pos].addSkillMaster(value);
            return true;
        }
        return false;
    }

    private boolean fillAttribShrine(final String attrib, final int pos, final String value) {
        if (attrib.equals("journalTag")) {
            this.records[pos].setShrineName(value);
            return true;
        }
        if (attrib.equals("normalDisabled")) {
            this.records[pos].setShrineNormalDisabled(value.equals("1"));
            return true;
        }
        if (attrib.equals("normalLocked")) {
            this.records[pos].setShrineNormalLocked(value.equals("1"));
            return true;
        }
        if (attrib.equals("epicDisabled")) {
            this.records[pos].setShrineEpicDisabled(value.equals("1"));
            return true;
        }
        if (attrib.equals("epicLocked")) {
            this.records[pos].setShrineEpicLocked(value.equals("1"));
            return true;
        }
        if (attrib.equals("legendaryDisabled")) {
            this.records[pos].setShrineLegendaryDisabled(value.equals("1"));
            return true;
        }
        if (attrib.equals("legendaryLocked")) {
            this.records[pos].setShrineLegendaryLocked(value.equals("1"));
            return true;
        }
        return false;
    }

    private boolean fillAttribSkillTree(final String attrib, final int pos, final String value) {
        if (attrib.startsWith("skillName")) {
            int i = 0;
            try {
                i = parseInt(attrib.substring(9));
            } catch (NumberFormatException ex) {
                i = 0;
            }
            this.records[pos].addMasterySkill(value, i);
            return true;
        }
        return false;
    }

    private boolean fillAttribSkill(final String attrib, final int pos, final String value, final int index) {
        int i = 0;
        boolean error = false;
        try {
            i = parseInt(value);
        } catch (NumberFormatException ex) {
            i = 0;
            error = true;
        }
        if (attrib.equals("buffSkillName")) {
            this.records[pos].setSkillBuffID(value);
            return true;
        }
        if (attrib.equals("petSkillName")) {
            this.records[pos].setPetBonusID(value);
            return true;
        }
        if (attrib.equals("skillBaseDescription")) {
            this.records[pos].setSkillDescription(value);
            return true;
        }
        if (attrib.equals("skillDisplayName")) {
            this.records[pos].setSkillNameTag(value);
            return true;
        }
        if (attrib.equals("skillMaxLevel")) {
            this.records[pos].setSkillMaxLevel(i);
            return true;
        }
        if (attrib.equals("skillTier")) {
            this.records[pos].setSkillTier(i);
            return true;
        }
        if (attrib.equals("skillDownBitmapName")) {
            this.records[pos].setSkillBitmapDownID(value);
            return true;
        }
        if (attrib.equals("skillUpBitmapName")) {
            this.records[pos].setSkillBitmapUpID(value);
            return true;
        }
        if (attrib.equals("skillConnectionOff")) {
            this.records[pos].addSkillConnectionOff(value, index);
            return true;
        }
        if (attrib.equals("skillConnectionOn")) {
            this.records[pos].addSkillConnectionOn(value, index);
            return true;
        }
        if (attrib.equals("skillDependancyAll")) {
            this.records[pos].setDependencyAll(i != 0);
            return true;
        }
        if (attrib.equals("skillDependancy")) {
            this.records[pos].addSkillDependency(value);
            return true;
        }
        if (attrib.equals("skillExperienceLevels")) {
            this.records[pos].addSkillXPLevel(value);
            return true;
        }
        if (attrib.equals("skillChargeLevel")) {
            this.records[pos].setSkillLevel(i);
            return true;
        }
        if (attrib.equals("skillChargeDuration")) {
            this.records[pos].setSkillDuration(i);
            return true;
        }
        if (attrib.equals("spawnObjects") || attrib.equals("modSpawnObjects")) {
            this.records[pos].addSpawnPet(index, value);
            return true;
        }
        return false;
    }

    private boolean fillAttribSkillBonus(final String attrib, final int pos, final String value, final int index) {
        if (attrib.startsWith("augmentMasteryName") || attrib.startsWith("augmentSkillName") || attrib.equals("itemSkillName") || attrib.equals("augmentAllLevel")) {
            String s = null;
            int type = 0;
            int idx = -1;
            String val = null;
            if (attrib.startsWith("augmentMasteryName")) {
                s = attrib.substring(18);
                type = 1;
                idx = parseInt(s);
                val = value;
            }
            if (attrib.startsWith("augmentSkillName")) {
                s = attrib.substring(16);
                type = 2;
                idx = parseInt(s);
                val = value;
            }
            if (attrib.equals("itemSkillName")) {
                type = 3;
                idx = 1;
                val = value;
            }
            if (attrib.equals("augmentAllLevel")) {
                type = 4;
                idx = 1;
                val = null;
            }
            DBSkillBonus.addEntity(this.records[pos].dbSkillBonuses, idx, type, val);
            if (!attrib.equals("augmentAllLevel")) {
                return true;
            }
        }
        if (attrib.startsWith("augmentMasteryLevel") || attrib.startsWith("augmentSkillLevel") || attrib.equals("itemSkillLevel") || attrib.equals("augmentAllLevel")) {
            String s = null;
            int type = 0;
            int idx = -1;
            if (attrib.startsWith("augmentMasteryLevel")) {
                s = attrib.substring(19);
                type = 1;
                idx = parseInt(s);
            }
            if (attrib.startsWith("augmentSkillLevel")) {
                s = attrib.substring(17);
                type = 2;
                idx = parseInt(s);
            }
            if (attrib.equals("itemSkillLevel")) {
                type = 3;
                idx = 1;
            }
            if (attrib.equals("augmentAllLevel")) {
                type = 4;
                idx = 1;
            }
            final int iVal = parseInt(value);
            DBSkillBonus.addValue(this.records[pos].dbSkillBonuses, idx, type, iVal, index);
            return true;
        }
        return false;
    }

    private boolean fillAttribPet(final String attrib, final int pos, final String value, final int index) {
        if (attrib.equals("charLevel")) {
            this.records[pos].setPetFormulaLevel(value);
            return true;
        }
        if (attrib.equals("characterAttributeEquations")) {
            this.records[pos].setPetBioID(value);
            return true;
        }
        if (attrib.equals("description")) {
            this.records[pos].setPetNameTag(value);
            return true;
        }
        if (attrib.equals("dyingSkillName")) {
            this.records[pos].setPetDieSkillID(value);
            return true;
        }
        if (attrib.startsWith("skillName")) {
            final String s = attrib.substring(9);
            final int i = parseInt(s);
            this.records[pos].addPetSkillsSkillID(i, value);
            return true;
        }
        if (attrib.startsWith("skillLevel")) {
            final String s = attrib.substring(10);
            final int i = parseInt(s);
            this.records[pos].addPetSkillsFormulaLevel(i, value);
            return true;
        }
        return false;
    }

    private boolean fillAttribPetBio(final String attrib, final int pos, final String value, final int index) {
        if (attrib.equals("characterLife")) {
            this.records[pos].setBioFormulaLife(value);
            return true;
        }
        if (attrib.equals("characterMana")) {
            this.records[pos].setBioFormulaMana(value);
            return true;
        }
        return false;
    }

    private boolean fillAttribController(final String attrib, final int pos, final String value) {
        int i = 0;
        boolean error = false;
        try {
            i = parseInt(value);
        } catch (NumberFormatException ex) {
            i = 0;
            error = true;
        }
        if (attrib.equals("chanceToRun")) {
            this.records[pos].setTriggerChance(i);
            return true;
        }
        if (attrib.equals("triggerType")) {
            this.records[pos].setTriggerType(value);
            return true;
        }
        return false;
    }

    private boolean fillAttribItemSet(final String attrib, final int pos, final String value) {
        if (attrib.equals("setDescription")) {
            this.records[pos].setItemSetDescriptionTag(value);
            return true;
        }
        if (attrib.equals("setMembers")) {
            this.records[pos].addItemSetItemID(value);
            return true;
        }
        if (attrib.equals("setName")) {
            this.records[pos].setItemSetNameTag(value);
            return true;
        }
        return false;
    }

    private boolean fillAttribLootTable(final String attrib, final int pos, final String value) {
        if (attrib.equals("bothPrefixSuffix")) {
            this.records[pos].setTableNormalPrefixSuffix(parseInt(value) > 0);
            return true;
        }
        if (attrib.equals("normalPrefixRareSuffix")) {
            this.records[pos].setTableNormalPrefixRareSuffix(parseInt(value) > 0);
            return true;
        }
        if (attrib.equals("rarePrefixNormalSuffix")) {
            this.records[pos].setTableRarePrefixNormalSuffix(parseInt(value) > 0);
            return true;
        }
        if (attrib.equals("rareBothPrefixSuffix")) {
            this.records[pos].setTableRarePrefixSuffix(parseInt(value) > 0);
            return true;
        }
        if (attrib.startsWith("lootName")) {
            this.records[pos].addTableItemID(value);
            return true;
        }
        if (attrib.startsWith("prefixTableLevelMax") || attrib.startsWith("suffixTableLevelMax") || attrib.startsWith("rarePrefixTableLevelMax") || attrib.startsWith("rareSuffixTableLevelMax")) {
            final String search = "TableLevelMax";
            final int len = search.length();
            final int p = attrib.indexOf(search);
            final String pre = attrib.substring(0, p);
            final String num = attrib.substring(p + len);
            final int i = parseInt(num);
            int type = 0;
            if (pre.equals("prefix")) {
                type = 1;
            }
            if (pre.equals("suffix")) {
                type = 2;
            }
            if (pre.equals("rarePrefix")) {
                type = 3;
            }
            if (pre.equals("rareSuffix")) {
                type = 4;
            }
            final int iVal = parseInt(value);
            this.records[pos].addTableMaxLevel(i, type, iVal);
            return true;
        }
        if (attrib.startsWith("prefixTableLevelMin") || attrib.startsWith("suffixTableLevelMin") || attrib.startsWith("rarePrefixTableLevelMin") || attrib.startsWith("rareSuffixTableLevelMin")) {
            final String search = "TableLevelMin";
            final int len = search.length();
            final int p = attrib.indexOf(search);
            final String pre = attrib.substring(0, p);
            final String num = attrib.substring(p + len);
            final int i = parseInt(num);
            int type = 0;
            if (pre.equals("prefix")) {
                type = 1;
            }
            if (pre.equals("suffix")) {
                type = 2;
            }
            if (pre.equals("rarePrefix")) {
                type = 3;
            }
            if (pre.equals("rareSuffix")) {
                type = 4;
            }
            final int iVal = parseInt(value);
            this.records[pos].addTableMinLevel(i, type, iVal);
            return true;
        }
        if (attrib.startsWith("prefixTableName") || attrib.startsWith("suffixTableName") || attrib.startsWith("rarePrefixTableName") || attrib.startsWith("rareSuffixTableName")) {
            final String search = "TableName";
            final int len = search.length();
            final int p = attrib.indexOf(search);
            final String pre = attrib.substring(0, p);
            final String num = attrib.substring(p + len);
            final int i = parseInt(num);
            int type = 0;
            if (pre.equals("prefix")) {
                type = 1;
            }
            if (pre.equals("suffix")) {
                type = 2;
            }
            if (pre.equals("rarePrefix")) {
                type = 3;
            }
            if (pre.equals("rareSuffix")) {
                type = 4;
            }
            this.records[pos].addTableAffixSetID(i, type, value);
            return true;
        }
        return false;
    }

    private boolean fillAttribLootTableSet(final String attrib, final int pos, final String value) {
        if (attrib.equals("levels")) {
            final int iVal = parseInt(value);
            this.records[pos].addTableSetMinLevel(iVal);
            return true;
        }
        if (attrib.equals("records")) {
            this.records[pos].addTableSetTableID(value);
            return true;
        }
        return false;
    }

    private boolean fillAttribFormula(final String attrib, final int pos, final String value) {
        if (attrib.equals("armorCostEquation") || attrib.equals("jewelryCostEquation") || attrib.equals("offhandCostEquation") || attrib.equals("shieldCostEquation") || attrib.equals("weaponCostEquation") || attrib.equals("weaponMelee2hCostEquation") || attrib.equals("weaponRangedCostEquation") || attrib.equals("weaponRanged2hCostEquation") || attrib.equals("daggerDexterityEquation") || attrib.equals("ranged1hDexterityEquation") || attrib.equals("ranged2hDexterityEquation") || attrib.equals("swordDexterityEquation") || attrib.equals("amuletIntelligenceEquation") || attrib.equals("chestIntelligenceEquation") || attrib.equals("daggerIntelligenceEquation") || attrib.equals("headIntelligenceEquation") || attrib.equals("offhandIntelligenceEquation") || attrib.equals("ringIntelligenceEquation") || attrib.equals("scepterIntelligenceEquation") || attrib.equals("axeStrengthEquation") || attrib.equals("chestStrengthEquation") || attrib.equals("feetStrengthEquation") || attrib.equals("handsStrengthEquation") || attrib.equals("headStrengthEquation") || attrib.equals("legsStrengthEquation") || attrib.equals("maceStrengthEquation") || attrib.equals("melee2hStrengthEquation") || attrib.equals("scepterStrengthEquation") || attrib.equals("shieldStrengthEquation") || attrib.equals("shouldersStrengthEquation") || attrib.equals("waistStrengthEquation")) {
            this.records[pos].addFormulaSetFormula(attrib, value.toUpperCase(GDConstants.LOCALE_US));
            return true;
        }
        return false;
    }

    private boolean fillEnginePlayer(final String attrib, final int pos, final String value, final int index) throws GDParseException {
        int i = 0;
        boolean error = false;
        try {
            i = parseInt(value);
        } catch (NumberFormatException ex) {
            i = 0;
            error = true;
        }
        if (attrib.equals("characterDexterity")) {
            if (error) {
                final Object[] args = {this.records[pos].getFileName(), attrib, value};
                final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_TAG_INVALID_VALUE", args);
                GDMsgLogger.addError(msg);
            }
            this.records[pos].setPlayerBaseDex(i);
            return true;
        }
        if (attrib.equals("characterIntelligence")) {
            if (error) {
                final Object[] args = {this.records[pos].getFileName(), attrib, value};
                final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_TAG_INVALID_VALUE", args);
                GDMsgLogger.addError(msg);
            }
            this.records[pos].setPlayerBaseInt(i);
            return true;
        }
        if (attrib.equals("characterLife")) {
            if (error) {
                final Object[] args = {this.records[pos].getFileName(), attrib, value};
                final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_TAG_INVALID_VALUE", args);
                GDMsgLogger.addError(msg);
            }
            this.records[pos].setPlayerBaseLife(i);
            return true;
        }
        if (attrib.equals("characterMana")) {
            if (error) {
                final Object[] args = {this.records[pos].getFileName(), attrib, value};
                final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_TAG_INVALID_VALUE", args);
                GDMsgLogger.addError(msg);
            }
            this.records[pos].setPlayerBaseMana(i);
            return true;
        }
        if (attrib.equals("characterModifierPoints")) {
            if (error) {
                final Object[] args = {this.records[pos].getFileName(), attrib, value};
                final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_TAG_INVALID_VALUE", args);
                GDMsgLogger.addError(msg);
            }
            this.records[pos].addLevelStatPoints(i, index);
            return true;
        }
        if (attrib.equals("characterStrength")) {
            if (error) {
                final Object[] args = {this.records[pos].getFileName(), attrib, value};
                final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_TAG_INVALID_VALUE", args);
                GDMsgLogger.addError(msg);
            }
            this.records[pos].setPlayerBaseStr(i);
            return true;
        }
        if (attrib.equals("dexterityIncrement")) {
            if (error) {
                final Object[] args = {this.records[pos].getFileName(), attrib, value};
                final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_TAG_INVALID_VALUE", args);
                GDMsgLogger.addError(msg);
            }
            this.records[pos].setPlayerIncDex(i);
            return true;
        }
        if (attrib.equals("experienceLevelEquation")) {
            this.records[pos].setXPFormula(value.toUpperCase(GDConstants.LOCALE_US));
            return true;
        }
        if (attrib.equals("intelligenceIncrement")) {
            if (error) {
                final Object[] args = {this.records[pos].getFileName(), attrib, value};
                final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_TAG_INVALID_VALUE", args);
                GDMsgLogger.addError(msg);
            }
            this.records[pos].setPlayerIncInt(i);
            return true;
        }
        if (attrib.equals("lifeIncrement")) {
            if (error) {
                final Object[] args = {this.records[pos].getFileName(), attrib, value};
                final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_TAG_INVALID_VALUE", args);
                GDMsgLogger.addError(msg);
            }
            this.records[pos].setPlayerIncLife(i);
            return true;
        }
        if (attrib.equals("manaIncrement")) {
            if (error) {
                final Object[] args = {this.records[pos].getFileName(), attrib, value};
                final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_TAG_INVALID_VALUE", args);
                GDMsgLogger.addError(msg);
            }
            this.records[pos].setPlayerIncMana(i);
            return true;
        }
        if (attrib.equals("maxDevotionPoints")) {
            if (error) {
                final Object[] args = {this.records[pos].getFileName(), attrib, value};
                final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_TAG_INVALID_VALUE", args);
                GDMsgLogger.addError(msg);
            }
            this.records[pos].setPlayerMaxDevotion(i);
            return true;
        }
        if (attrib.equals("maxPlayerLevel")) {
            if (error) {
                final Object[] args = {this.records[pos].getFileName(), attrib, value};
                final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_TAG_INVALID_VALUE", args);
                GDMsgLogger.addError(msg);
            }
            this.records[pos].setPlayerMaxLevel(i);
            return true;
        }
        if (attrib.equals("skillModifierPoints")) {
            if (error) {
                final Object[] args = {this.records[pos].getFileName(), attrib, value};
                final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_TAG_INVALID_VALUE", args);
                GDMsgLogger.addError(msg);
            }
            this.records[pos].addLevelSkillPoints(i, index);
            return true;
        }
        if (attrib.startsWith("skillTree")) {
            this.records[pos].addMastery(attrib, value);
            return true;
        }
        if (attrib.equals("strengthIncrement")) {
            if (error) {
                final Object[] args = {this.records[pos].getFileName(), attrib, value};
                final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_TAG_INVALID_VALUE", args);
                GDMsgLogger.addError(msg);
            }
            this.records[pos].setPlayerIncStr(i);
            return true;
        }
        return false;
    }

    private boolean fillAttribInventoryGrid(final String attrib, final int pos, final String value) {
        int i = 0;
        boolean error = false;
        try {
            i = parseInt(value);
        } catch (NumberFormatException ex) {
            i = 0;
            error = true;
        }
        if (attrib.equals("inventoryX")) {
            this.records[pos].setXOffset(i);
            return true;
        }
        if (attrib.equals("inventoryXSize")) {
            this.records[pos].setXSize(i);
            return true;
        }
        if (attrib.equals("inventoryY")) {
            this.records[pos].setYOffset(i);
            return true;
        }
        if (attrib.equals("inventoryYSize")) {
            this.records[pos].setYSize(i);
            return true;
        }
        return false;
    }

    private boolean resolveSkillName(final ARZRecord record) {
        String skill = null;
        if (record.getPetBonusID() != null) {
            skill = record.getPetBonusID();
        }
        if (record.getSkillBuffID() != null) {
            skill = record.getSkillBuffID();
        }
        if (skill == null) {
            return false;
        }
        for (int i = 0; i < this.records.length; ++i) {
            if (this.records[i] != null) {
                if (this.records[i].getSkillNameTag() != null) {
                    if (skill.equals(this.records[i].getFileName())) {
                        record.setSkillNameTag(this.records[i].getSkillNameTag());
                        return true;
                    }
                }
            }
        }
        return false;
    }

    private void resolveGrantedSkillName(final ARZRecord record) {
        for (final DBSkillBonus bonus : record.dbSkillBonuses) {
            if (bonus.getEntity() == null) {
                continue;
            }
            for (int i = 0; i < this.records.length; ++i) {
                if (this.records[i] != null) {
                    if (this.records[i].getSkillName() != null || this.records[i].getSkillBuffID() != null || this.records[i].getPetBonusID() != null) {
                        if (bonus.getEntity().equals(this.records[i].getFileName())) {
                            if (this.records[i].getSkillName() != null) {
                                bonus.setEntityName(this.records[i].getSkillName());
                                break;
                            }
                            break;
                        }
                    }
                }
            }
        }
    }

    private void resolveDevotionFlag(final ARZRecord record) {
        for (int i = 0; i < this.records.length; ++i) {
            if (this.records[i] != null) {
                if (record.getSkillBuffID().equals(this.records[i].getFileName())) {
                    record.setDevotion(this.records[i].isDevotion());
                    break;
                }
            }
        }
    }

    private void resolveBonusIncrementFlag(final ARZRecord record) {
        for (final DBSkillBonus bonus : record.dbSkillBonuses) {
            if (bonus.getEntity() == null) {
                continue;
            }
            if (bonus.getValue() < 1) {
                continue;
            }
            for (int i = 0; i < this.records.length; ++i) {
                if (this.records[i] != null) {
                    if (bonus.getEntity().equals(this.records[i].getFileName())) {
                        this.records[i].setSkillBonusIncrement(true);
                        break;
                    }
                }
            }
        }
    }

    private void resolveModifiedSkillFlag(final ARZRecord record) {
        for (final DBSkillModifier modif : record.getSkillModifierList()) {
            if (modif.getSkillID() == null) {
                continue;
            }
            for (int i = 0; i < this.records.length; ++i) {
                if (this.records[i] != null) {
                    if (modif.getSkillID().equals(this.records[i].getFileName())) {
                        this.records[i].setSkillModified(true);
                        break;
                    }
                }
            }
        }
    }

    private void resolveAttrib() {
        for (int i = 0; i < this.records.length; ++i) {
            if (this.records[i] != null) {
                if (this.records[i].getItemSetID() != null) {
                    this.records[i].setItemSetNameTag(this.getAttribValue(this.records[i].getItemSetID(), "itemSetName"));
                }
                if (this.records[i].getItemSkillLevelFormula() != null) {
                    this.records[i].processItemSkillLevelFormula();
                }
            }
        }
        boolean changed = true;
        while (changed) {
            changed = false;
            for (int j = 0; j < this.records.length; ++j) {
                if (this.records[j] != null) {
                    if (this.records[j].isSkill() && this.records[j].getSkillNameTag() == null) {
                        final boolean b = this.resolveSkillName(this.records[j]);
                        changed = (changed || b);
                    }
                }
            }
        }
        for (int j = 0; j < this.records.length; ++j) {
            if (this.records[j] != null) {
                if (this.records[j].dbSkillBonuses != null && !this.records[j].dbSkillBonuses.isEmpty()) {
                    this.resolveGrantedSkillName(this.records[j]);
                }
            }
        }
        for (int j = 0; j < this.records.length; ++j) {
            if (this.records[j] != null) {
                if (this.records[j].getFileName().startsWith("records/skills/") && this.records[j].getSkillBuffID() != null) {
                    this.resolveDevotionFlag(this.records[j]);
                }
            }
        }
    }

    private String getAttribValue(final String filename, final String attrib) {
        String value = null;
        for (int i = 0; i < this.records.length; ++i) {
            if (this.records[i] != null) {
                if (this.records[i].getFileName().equals(filename)) {
                    value = this.records[i].getItemSetNameTag();
                    break;
                }
            }
        }
        return value;
    }

    public boolean insertData(final boolean suppressTagWarning) {
        return GDDBData.insertData(this.records, suppressTagWarning);
    }

    public void extractRecords(final String dir) {
        try {
            final File file = new File(this.filename);
            if (!file.exists()) {
                final Object[] args = {this.filename};
                final String s = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_FILE_NOT_FOUND", args);
                throw new FileNotFoundException(s);
            }
            if (!file.isFile()) {
                final Object[] args = {this.filename};
                final String s = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_FILE_NOT_FOUND", args);
                throw new FileNotFoundException(s);
            }
            if (!file.canRead()) {
                final Object[] args = {this.filename};
                final String s = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_FILE_CANNOT_READ", args);
                throw new IOException(s);
            }
            GDBuffer buffer = new GDRandomAccessBuffer(file);
            try {
                this.header = getHeader(buffer);
                this.strings = this.getStrings(buffer);
                this.records = this.getRecords(buffer);
                this.recordsToText(buffer, dir);
            } catch (IOException ex) {
                throw ex;
            } finally {
                buffer.close();
                buffer = null;
            }
        } catch (Exception ex2) {
            GDMsgLogger.addError(ex2);
        }
        if (GDMsgLogger.severeErrorsInLog()) {
            GDMsgLogger.addError(GDMsgFormatter.getString(GDMsgFormatter.rbMsg, "ERR_DB_EXTRACT_FAIL"));
        }
    }

    private void recordsToText(final GDBuffer buffer, final String dir) throws IOException, GDParseException {
        final NumberFormat formatter = new DecimalFormat("#0.000000");
        final LZ4Factory factory = LZ4Factory.fastestInstance();
        final LZ4FastDecompressor decomp = factory.fastDecompressor();
        for (int i = 0; i < this.records.length; ++i) {
            if (this.records[i] != null) {
                this.records[i].setFileName(this.strings[this.records[i].strID].str);
                final byte[] bComp = buffer.getByteArray(this.records[i].offset + 24, this.records[i].len_comp);
                final byte[] bDecomp = new byte[this.records[i].len_decomp];
                decomp.decompress(bComp, bDecomp);
                String text = "";
                String value = "";
                int offset = 0;
                try {
                    while (offset < bDecomp.length) {
                        final int typeOffset = offset;
                        final short varType = GDReader.getUShort(bDecomp, offset);
                        offset += 2;
                        final short count = GDReader.getUShort(bDecomp, offset);
                        offset += 2;
                        final int strIdx = GDReader.getUInt(bDecomp, offset);
                        offset += 4;
                        final String tag = this.strings[strIdx].str + ",";
                        String values = "";
                        for (int j = 0; j < count; ++j) {
                            switch (varType) {
                                case 0: {
                                    final int valInt = GDReader.getInt(bDecomp, offset);
                                    value = String.valueOf(valInt);
                                    break;
                                }
                                case 1: {
                                    final float valFloat = GDReader.getFloat(bDecomp, offset);
                                    value = formatter.format(valFloat);
                                    break;
                                }
                                case 2: {
                                    final int valStrIdx = GDReader.getUInt(bDecomp, offset);
                                    value = this.strings[valStrIdx].str;
                                    break;
                                }
                                case 3: {
                                    final boolean valBool = GDReader.getBool(bDecomp, offset);
                                    if (valBool) {
                                        value = "1";
                                        break;
                                    }
                                    value = "0";
                                    break;
                                }
                                default: {
                                    final Object[] args = {this.records[i].getFileName(), this.strings[strIdx].str};
                                    final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_UNKNOWN_VAR_TYPE", args);
                                    throw new GDParseException(msg, typeOffset);
                                }
                            }
                            offset += 4;
                            values += value;
                            if (j == count - 1) {
                                values += ",";
                            } else {
                                values += ";";
                            }
                        }
                        if (!values.equals("0,") && !values.equals("0.000000,")) {
                            text = text + tag + values + GDConstants.LINE_SEPARATOR;
                        }
                    }
                } catch (GDParseException ex) {
                    GDMsgLogger.addError(ex);
                    this.records[i].error = true;
                    final int pos = this.records[i].getFileName().lastIndexOf(".");
                    if (pos != -1) {
                        this.records[i].setFileName(this.records[i].getFileName().substring(0, pos));
                    }
                    this.records[i].setFileName(this.records[i].getFileName() + ".err");
                }
                final String osName = GDWriter.getOSFilePath(this.records[i].getFileName());
                final String newName = dir + GDConstants.FILE_SEPARATOR + osName;
                try {
                    GDWriter.write(newName, text);
                } catch (Exception ex2) {
                    GDMsgLogger.addError(ex2);
                }
            }
        }
    }

    private boolean fillAttribCaravanWindow(final String attrib, final int pos, final String value) {
        int i = 0;
        boolean error = false;
        try {
            i = parseInt(value);
        } catch (NumberFormatException ex) {
            i = 0;
            error = true;
        }
        if (attrib.equals("InventoryHeight")) {
            this.records[pos].setYSize(i);
            return true;
        }
        if (attrib.equals("InventoryWidth")) {
            this.records[pos].setXSize(i);
            return true;
        }
        if (attrib.equals("WindowLocationX")) {
            this.records[pos].setXOffset(i);
            return true;
        }
        if (attrib.equals("WindowLocationY")) {
            this.records[pos].setYOffset(i);
            return true;
        }
        return false;
    }
}
